#! /bin/bash -e

#####################################################################
#                                                                   #
#               Compiles Faust programs to puredata                 #
#               (c) Grame, 2009-2024                                #
#                                                                   #
#####################################################################

. faustpath
. faustoptflags
. usage.sh

CXXFLAGS+=" $MYGCCFLAGS"  # So that additional CXXFLAGS can be used

COMPILE=yes
ARCHFILE=$FAUSTARCH/puredata.cpp

NEWIO="0"

echoHelp()
{
    usage faust2puredata "[options] [Faust options] <file.dsp>"
    platform Linux
    require PureData
    echo "Compiles Faust programs to PureData"
    option -arch32 "compile a 32 bits architecture."
    option -arch64 "compile a 64 bits architecture."
    option -poly "generates a polyphonic self-contained DSP."
    option -newio "use new inlet and outlet structure."
    option -tosource "skip the C++ compiling step and only generate the C++ source file."
    option "Faust options"
    exit
}

if [ "$#" -eq 0 ]; then
    echo 'Please, provide a Faust file to process !'
    echo ''
    echoHelp
fi

#-------------------------------------------------------------------
# Analyze command arguments :
# faust options                 -> OPTIONS
# if -omp : -openmp or -fopenmp -> OPENMP
# existing *.dsp files          -> FILES
#

# dispatch command arguments
for p in $@; do

    if [ $p = "-help" ] || [ $p = "-h" ]; then
        echoHelp
    elif [ $p = "-arch32" ]; then
        PROCARCH="-m32 -L/usr/lib32"
    elif [ $p = "-poly" ]; then
        F2PDPOLY="-n 8"
    elif [ $p = "-arch64" ]; then
        PROCARCH="-m64"
    elif [ $p = "-newio" ]; then
        NEWIO="1"
    elif [ $p = "-tosource" ]; then
        COMPILE=no
    elif [ ${p:0:1} = "-" ]; then
        OPTIONS="$OPTIONS $p"
    elif [[ -f "$p" ]] && [ ${p: -4} == ".dsp" ]; then
        FILES="$FILES $p"
    else
        OPTIONS="$OPTIONS $p"
    fi
done
        
#-------------------------------------------------------------------
# Check darwin specifics
#
if [[ $(uname) == Darwin || $CROSSTARGET == Darwin ]]; then
    LIB="-I$PUREDATA_MACSDK -I. -bundle -undefined suppress -flat_namespace"
    EXT="~.pd_darwin"
else
    LIB="-I$PUREDATA_LINUXSDK -I. -fPIC -shared"
    EXT="~.pd_linux"
fi

#-------------------------------------------------------------------
# compile the *.dsp files
#
for p in $FILES; do

    CUR=$(pwd)
    f=$(basename "$p")
    SRCDIR=$(dirname "$p")

    # creates a temporary dir
    TDR=$(mktemp -d faust.XXXXXX)
    TMP=$TDR/${f%.dsp}
    mkdir "$TMP"

    # case where a foreign C++ function is called in the Faust code (TODO: this is only a quick fix!)
    count=`ls -1 *.h 2>/dev/null | wc -l`
    if [ $count != 0 ]; then
        cp *.h $TMP
    fi

    # compile faust to c++ and xml
    faust -xml "$SRCDIR/$f" -o /dev/null || exit
    mv "$SRCDIR/$f.xml" $TMP/
    CXX_SOURCE="$TMP/${f%.dsp}.cpp"
    faust -i -a $ARCHFILE $OPTIONS "$SRCDIR/$f" -o $CXX_SOURCE || exit

    # compile c++ to binary
    if [ "$COMPILE" == "yes" ]
    then
        (
        cd "$TMP"
        CXX_SOURCE=${f%.dsp}.cpp
        if [[ $(uname) == Darwin || $CROSSTARGET == Darwin ]]; then
            # universal binaries produced on M1
            if [ $(uname -p) == arm ]; then
                $CXX -arch arm64 $CXXFLAGS  $FAUSTTOOLSFLAGS -DNEWIO=$NEWIO $OMP $LIB -Dmydsp=${f%.dsp} -o ${f%.dsp}.arm64 $CXX_SOURCE || exit
                $CXX -arch x86_64 $CXXFLAGS $FAUSTTOOLSFLAGS -DNEWIO=$NEWIO $OMP $LIB -Dmydsp=${f%.dsp} -o ${f%.dsp}.x86_64 $CXX_SOURCE || exit
                $LIPO -create "${f%.dsp}.arm64" "${f%.dsp}.x86_64" -output "${f%.dsp}$EXT" || exit
            else
                $CXX $CXXFLAGS $FAUSTTOOLSFLAGS -DNEWIO=$NEWIO $OMP $LIB -Dmydsp=${f%.dsp} -o "${f%.dsp}$EXT" $CXX_SOURCE || exit
            fi
            if which codesign > /dev/null; then
                codesign --sign - --deep --force "${f%.dsp}$EXT"
            fi
        else
            $CXX $CXXFLAGS $FAUSTTOOLSFLAGS $PROCARCH $OMP $LIB -Dmydsp=${f%.dsp} -o ${f%.dsp}$EXT $CXX_SOURCE || exit
        fi
        if [ $(which faust2pd) ]; then
            if [ "$NEWIO" == "0" ]; then
                faust2pd -s $F2PDPOLY $f.xml
            else
                echo "WARNING : -newio cannot yet be used with faust2pd"
            fi
        fi
        ) > /dev/null || exit
     
        rm -rf "$SRCDIR/${f%.dsp}$EXT"
        cp "$TMP/${f%.dsp}$EXT" "$SRCDIR/${f%.dsp}$EXT"
        # collects all the files produced
        OUTPUTS="$OUTPUTS$SRCDIR/${f%.dsp}$EXT;"
        if [[ $(which faust2pd) && "$NEWIO" == "0" ]]; then
            cp "$TMP/${f%.dsp}.pd" "$SRCDIR/${f%.dsp}.pd"
            OUTPUTS="$OUTPUTS$SRCDIR/${f%.dsp}.pd;"
        fi
        rm -rf "$TDR"
    else
        OUTPUTS="$OUTPUTS $CXX_SOURCE"
    fi

done

# return the binaries names
echo "$OUTPUTS"

